#include "ExcelOOXMLFile.h"
#include <fstream>

ExcelOOXMLFile::ExcelOOXMLFile(string filePath)
{
	fileResult = SUCCESS;
	ReadContent(filePath);
}


ExcelOOXMLFile::~ExcelOOXMLFile()
{
}

std::string ExcelOOXMLFile::ParagraphText()
{
	return _paragraphText;
}

ERRORTYPE ExcelOOXMLFile::getResult()
{
	return fileResult;
}

void ExcelOOXMLFile::ReadContent(string filePath)
{
#ifdef _WIN32
	wchar_t dst[MAX_PATH];
	int length = 0;
	GbkToUnicode(filePath.c_str(), nullptr, length);
	GbkToUnicode(filePath.c_str(), dst, length);

	HZIP hz = OpenZip(dst, 0);
#else
	HZIP hz = OpenZip(filePath.c_str(), 0);
#endif
	if (hz == NULL)
	{
		fileResult = FILE_OPEN_FAILED;
		return;
	}
	ZIPENTRY ze;
	GetZipItem(hz, -1, &ze); 
	int numitems = ze.index;
	int index = 1;
	wchar_t txtPath[MAX_PATH];

   _getValueArray(hz);

	while (1)
	{
		
 		char xml_file[MAX_PATH] = { 0 };
		sprintf(xml_file, "xl/worksheets/sheet%d.xml", index++ );
		
		int i = 0;
#ifdef _WIN32
		int length = 0;
		GbkToUnicode(xml_file, nullptr, length);
		GbkToUnicode(xml_file, txtPath, length);
		ZRESULT result = FindZipItem(hz, txtPath, true, &i, &ze);
#else
		ZRESULT result = FindZipItem(hz, xml_file, true, &i, &ze);
#endif
		if (result == 0)
		{
			char *ibuf = new char[ze.unc_size];
			UnzipItem(hz, i, ibuf, ze.unc_size);

			tinyxml2::XMLDocument excel;

			excel.Parse(ibuf, ze.unc_size);


			XMLElement* root = excel.RootElement();
			parseBody(root);
			delete ibuf;
		}
		else
		{
			if (index == 2)
			{
				fileResult = FILE_NOT_XLSX;
			}
		
			break;
		}
	}

	std::vector<LineInfo> arr = std::move(getSheetArray());
	
	for(auto var: arr)
	{
		
			for (int i = 0; i< var.array.size(); i++)
			{

				_paragraphText.append(var.array.at(i));
			}
	}

	CloseZip(hz);
}

void  ExcelOOXMLFile::_getValueArray(HZIP hz)
{
	ZIPENTRY ze;


	int i = 0;
	ZRESULT ret = FindZipItem(hz, _T("xl/sharedStrings.xml"), true, &i, &ze);
   // ret = FindZipItem(hz, _T("xl\\sharedStrings.xml"), true, &i, &ze);
	if (ret == 0)
	{
		char *ibuf = new char[ze.unc_size];
		UnzipItem(hz, i, ibuf, ze.unc_size);
		tinyxml2::XMLDocument doc;
		doc.Parse((const char*)ibuf, ze.unc_size);
		XMLElement *root = doc.RootElement();
		XMLElement *siElement = root->FirstChildElement("si");
		while (siElement)
		{	
			std::string temp = "";
			
			auto tElement = siElement->FirstChildElement("t");

			while (tElement)
			{
				if (tElement->Attribute("xml:space","preserve"))
				{
				
					temp = temp + " ";
				}
				else if (tElement->Attribute("t/"))
				{
					temp = temp + " ";
				}
				else
				{
					const char * text = tElement->GetText();
					if (text)
					{
						temp = temp + string(text);
					}
				//	temp = temp + tElement->GetText();

				}
				tElement = tElement->NextSiblingElement("t");
			}
			valueArray.push_back(temp);
			siElement = siElement->NextSiblingElement("si");
		}
		delete ibuf;
	}
	else
	{
		return ;
	}
	
}

void ExcelOOXMLFile::deleteNum(std::string &content)
{
	string::iterator t = content.begin();
	while (t != content.end())
	{
		if (*t >= '0' && *t <= '9')
		{
			content.erase(t);
		}
		else
		{
			t++;
		}
	}
}
bool ExcelOOXMLFile::isNumber(std::string &content)
{
	string::iterator t = content.begin();
	bool res = true;
	while (t != content.end())
	{
		if ((*t <= '9' && *t >= '0') || *t =='.')
		{
			t++;
			
		}
		else
		{
			res = false;
			break;
		}
	
	}
	return res;
}

int ExcelOOXMLFile::getColIndex(std::string &content)
{
	auto returnValue = 0;
	for (auto i = 0; i < content.length(); i++)
	{
		char n = content[i];
		auto cValue = n - 64;
		returnValue *= 26;
		returnValue += cValue;
	}
	return returnValue - 1;
}

void ExcelOOXMLFile::parseBody(XMLElement * root)
{
	XMLElement * sheetDataElement = root->FirstChildElement("sheetData");
	XMLElement * rowElement = sheetDataElement->FirstChildElement("row");
	std::map<int, LineInfo> excelHash;// = new std::map<int, LineInfo>;
	while (rowElement)
	{
		LineInfo lineInfo;
		auto rowIndex = atoi(rowElement->Attribute("r")) - 1;
		lineInfo.lineIndex = rowIndex;
		std::vector<std::string> &rowArray = lineInfo.array;
		auto cElement = rowElement->FirstChildElement("c");
		
		while (cElement)
		{
			
			std::string cc = cElement->Attribute("r");
			deleteNum(cc);
			auto colIndex = getColIndex(cc);
			std::string t = "";
			std::string v = "";

			if (cElement->Attribute("t"))
			{
				t = cElement->Attribute("t");
			}
			auto vElement = cElement->FirstChildElement("v");
			
			if (vElement)
			{
				if (t != "str")
				{
					v = vElement->GetText();
					if (!isNumber(v))
					{
						cElement = cElement->NextSiblingElement("c");
						continue;
					}
				}
				
			}
			if (rowArray.size() < colIndex)
			{
				int len = rowArray.size();
				for (auto i = 0; i < colIndex - len; i++)
				{
					rowArray.push_back(""); //
				}
			}
			if (t == "s")
			{
				
				rowArray.push_back(valueArray[atoi(v.c_str())]);
			}
			else
			{
				rowArray.push_back(v);
			}
			cElement = cElement->NextSiblingElement("c");
		}
		auto bb = false;
		for (auto iii : rowArray)
		{
			if (iii.length() > 1)
			{
				bb = true;
				break;
			}
		}
		if (bb)
		{
			excelHash[rowIndex] = lineInfo;
			//excelHash->insert(make_pair(rowIndex,lineInfo));
		}
		rowElement = rowElement->NextSiblingElement("row");
	}
	vecExcel.push_back(excelHash);

}

std::vector<LineInfo> ExcelOOXMLFile::getSheetArray()
{
	std::vector<LineInfo> result;

	for (auto vec : vecExcel)
	{
	
		for (auto ite = vec.begin(); ite != vec.end(); ite++)
		{
			auto &lineInfo_ = ite->second;
			result.push_back(lineInfo_);
		}
	}
	
	return result;
}
